package com.sunseen.capacitormachine.commumication.tcp;

import android.util.Log;

import com.sunseen.capacitormachine.common.event.ConnectStateChangeEvent;

import org.greenrobot.eventbus.EventBus;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.FixedLengthFrameDecoder;

public class InfraredDataServer {
    private static final String TAG = InfraredDataServer.class.getSimpleName();

    private final int port;
    /**
     * 由于红外检测模块分为两个集群，用portId标识哪个模块集群，0表示接近进料端的模块,1表示接近出料端的模块
     * 主要用于索引对应模块中链路号对应的烤箱夹具队列的夹具的队列号
     * 详情对应表请查看{@link  com.sunseen.capacitormachine.data.Constant#HolderPosTable}
     */
    private final int portId;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel channel;
    private SocketChannel clientSocketChannel;

    private ParseHandler parseHandler;

    InfraredDataServer(int port, int portId) {
        this.port = port;
        this.portId = portId;
        //用来接收进来的连接
        bossGroup = new NioEventLoopGroup();
        //用来处理已经被接收的连接，一旦bossGroup接收到连接，就会把连接信息注册到workerGroup
        workerGroup = new NioEventLoopGroup();
    }

    public void start() {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        clientSocketChannel = socketChannel;
                        clientSocketChannel.pipeline().addLast(new FixedLengthFrameDecoder(13));
                        parseHandler = new ParseHandler();
                        parseHandler.init(portId);
                        clientSocketChannel.pipeline().addLast(parseHandler);
                    }
                });
        ChannelFutureListener listener = new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()) {
                    EventBus.getDefault().post(new ConnectStateChangeEvent(portId, false));
                    Log.e(TAG, "port" + port + " 连接成功");
                } else {
                    EventBus.getDefault().post(new ConnectStateChangeEvent(portId, true));
                    Log.e(TAG, "port" + port + " 连接失败 cause:" + channelFuture.cause());
                }
            }
        };
        channel = serverBootstrap.bind(port).addListener(listener).channel();
    }

    private void fireBytes(byte[] bytes) {
        if (clientSocketChannel != null) {
            ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes);
            clientSocketChannel.pipeline().fireUserEventTriggered(byteBuf);
        }
    }

    private static final byte[] PauseCmd = new byte[]{0x88 - 256, 0x02, 0xFF - 256, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    private static final byte[] StartCmd = new byte[]{0x88 - 256, 0x02, 0xFF - 256, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0};

    void sendCmd(boolean start) {
        if (start) {
            fireBytes(StartCmd);
        } else {
            fireBytes(PauseCmd);
        }
    }

    void sendParams(int implosionTime, int implosionCurrentHighLimit, int implosionCurrentLowLimit,
                    int implosionVoltageHighLimit, int implosionVoltageLowLimit) {
        byte[] paramBytes = new byte[]{0x88 - 256, 0x01, 0xFF - 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
        paramBytes[3] = (byte) (implosionTime >> 8);
        paramBytes[4] = (byte) (implosionTime & 0xFF);
        paramBytes[5] = (byte) (implosionCurrentHighLimit >> 8);
        paramBytes[6] = (byte) (implosionCurrentHighLimit & 0xFF);
        paramBytes[7] = (byte) (implosionCurrentLowLimit >> 8);
        paramBytes[8] = (byte) (implosionCurrentLowLimit & 0xFF);
        paramBytes[9] = (byte) (implosionVoltageHighLimit >> 8);
        paramBytes[10] = (byte) (implosionVoltageHighLimit & 0xFF);
        paramBytes[11] = (byte) (implosionVoltageLowLimit >> 8);
        paramBytes[12] = (byte) (implosionVoltageLowLimit & 0xFF);
        fireBytes(paramBytes);
    }

    void stop() {
        if (channel != null) {
            channel.close();
        }
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}
